# 中间件是  django 很重要的一部分，它在请求和响应之间充当预处理器的角色。
# 很多通用的逻辑可以放到这里，django 会自动的调用他们。
# 在这里，我们写了一个简单的中间件来处理 PUT 请求。只要是 PUT 请求，我们就对它作这样的
# 处理。所以，当你对某个请求都有相同的处理操作时，可以把它写在中间件里。所以，中间件是什么呢？
# 中间件只是视图函数的公共部分。你把中间件的核心处理逻辑复制粘贴到视图函数中也是能够正常运行的。

from django.http import QueryDict


# QueryDict 是 django 专门为请求的查询字符串做的数据结构，它类似字典，但是又不是字典。
# request 对象的 POST GET 属性都是这样的字典。
# 类似字典，是因为 QueryDict 和 python 的 dict 有相似的 API 接口，所以你可以把它当字典
# 来调用。
# 不是字典，是因为 QueryDict 允许同一个键有多个直。比如 {'a':[‘1’,‘2’]}，a 同时有值 1 和 2，
# 所以，一般不要用 QueryDict[key] 的形式来访问相应 key 的值，因为你得到的会是一个列表，而不是
# 一个单一的值，应该用 QueryDict.get(key) 来获取你想要的值，除非你知道你在干什么，你才能
# 这样来取值。为什么会允许多个值呢，因为 GET
# 请求中，常常有这种参数 http://www.example.com/?action=search&achtion=filter ，
# action 在这里有两个值，有时候我们需要对这两个值都作出响应。但是当你用 .get(key) 方法取值的
# 时候，只会取到最新的一个值。如果确实需要访问这个键的多个值，应该用 .getList(key) 方法来访问，
# 比如刚才的例子应该用 request.GET.getList('action') 来访问 action 的多个值。
# 同理，对于 POST 请求也应该这么做。
# 由于原生的 request 对象并没有 PUT 属性，所以我们需要在中间件中加上这个属性，这样我们
# 就可以在视图函数中用 request.PUT 来访问 PUT 请求中的参数值了。

# 中间件在 1.11 版本里是一个可调用对象，和之前的类中间件不同。既然是可调用对象，那就有
# 两种写法，一种是函数，因为函数就是一个可调用对象；一种是自己用类来写一个可调用对象，也就是
# 包含 __cal__() 方法的类。

def put_middleware(get_response):
    # 在 1.11 版本中，中间件对象应该接收一个 get_response 的参数，这个参数用来获取上一个
    # 中间件处理之后的响应，每个中间件处理完请求之后都应该用这个函数来返回一个响应，我们不需要
    # 关心这个 get_response 函数是怎么写的，是什么东西，只需要记得在最后调用它，返回响应就好。
    # 这个最外层函数应该返回一个函数，用作真正的中间件处理。

    # 在这个地方写你的预处理逻辑，比如配置什么的。当然，你也可以在被返回的函数中写配置和浴池里
    # 但是这么做有时候就有些不直观，配置、预处理和核心逻辑分开，让看代码的人一眼就明白
    # 这个中间件是在做什么。
    # 最通常的例子是，很多的 API 会对请求做许多的处理，比如记录下这个请求的 IP 地址
    # 就可以先在这里做这个步骤；又比如，为了控制访问频率，可以先读取数据库中的访问数据，
    # 根据访问数据记录来决定要不要让这个请求进入到视图函数中。
    # 我们对 PUT 请求并没有什么预处理或者配置操作要进行，所以就什么都没写
    def middleware(request):
        if request.method == 'PUT':  # 如果是 PUT 请求
            setattr(request, 'PUT', QueryDict(request.body))  # 给请求设置 PUT 属性，这样我们就可以在视图函数中访问这个属性了
            # request.body 是请求的主体。我们知道请求有请求头，那请求的主体就是
            # request.body 了。当然，你一定还会问，为什么这样就可以访问 PUT 请求的相关
            # 数据了呢？这涉及到了 http 协议的知识，这里就不展开了，有兴趣的同学可以自行查阅资料
        response = get_response(request)  # 使用 get_response 返回响应
        return response  # 返回响应

    return middleware  # 返回核心的中间件处理函数
